package xtu.www.viewinject.net;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;

import android.util.Pair;


/**
 * Creator  ming
 * Date     17/8/11
 * Email    skyar@live.cn
 */
public class SimpleTokener {
    private final String in;

    private int pos;

    public SimpleTokener(String in) {
        // consume an optional byte order mark (BOM) if it exists
        if (in != null && in.startsWith("\ufeff")) {
            in = in.substring(1);
        }
        this.in = in;
    }

    /**
     * 解析 json 的一级结构
     * @param json 需要解析json传
     */
    public static JSONObject getOneLevelJOSNObject(String json) {
        JSONObject jsonObject = new JSONObject();

        SimpleTokener tokener = new SimpleTokener(json);
        try {
            Pair<String, Object> pair = tokener.nextPair();
            while (pair != null) {
                jsonObject.put(pair.first, pair.second);
                pair = tokener.nextPair();
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return jsonObject;
    }

    /**
     * 解析 json 的一级结构，返回 HashMap
     * @param json 需要解析json传
     */
    public static HashMap<String, Object> getHashMap(String json) {
        HashMap<String, Object> map = new HashMap<>();

        SimpleTokener tokener = new SimpleTokener(json);
        try {
            Pair<String, Object> pair = tokener.nextPair();
            while (pair != null) {
                map.put(pair.first, pair.second);
                pair = tokener.nextPair();
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return map;
    }

    private Pair<String, Object> nextPair() throws JSONException {

        int c = nextCleanInternal();
        while (true) {
            if (c == -1) {
                throw syntaxError("Invalid json");
            } else if (c == '"') {
                break;
            } else if (c == '}') {
                return null;
            } else {
                c = nextCleanInternal();
            }
        }
        String key = nextString((char) c);

        int separator = nextCleanInternal();
        if (separator != ':' && separator != '=') {
            throw syntaxError("Expected ':' after " + key);
        }

        int v = nextCleanInternal();
        Object value;

        switch (v) {
            case -1:
                return null;
            case '{':
                pos--;
                value = readObjectString();
                break;
            case '[':
                pos--;
                value = readArrayString();
                break;
            case '\'':
            case '"':
                value = nextString((char) c);
                break;
            default:
                pos--;
                value = readLiteral();
        }

        return new Pair<>(key, value);
    }

    private String readArrayString() throws JSONException {
        int start = pos;
        int count = 0;
        // 忽略字符串中的 [, ]
        boolean isInString = false;

        while (true) {
            int c = nextCleanInternal();

            if (c == -1) {
                break;
            } else if (c == '[') {
                if (!isInString) {
                    count++;
                }
            } else if (c == ']') {
                if (!isInString) {
                    count--;
                    if (count == 0) {
                        break;
                    }
                }
            } else if (c == '"') {
                isInString = !isInString;
            } else if (c == '\\') {
                pos++;
            }
        }

        return in.substring(start, pos);
    }

    private String readObjectString() throws JSONException {
        int start = pos;
        int count = 0;
        // 忽略字符串中的 {，}
        boolean isInString = false;

        while (true) {
            int c = nextCleanInternal();

            if (c == -1) {
                break;
            } else if (c == '{') {
                if (!isInString) {
                    ++count;
                }
            } else if (c == '}') {
                if (!isInString) {
                    --count;
                    if (count == 0) {
                        break;
                    }
                }
            } else if (c == '"') {
                isInString = !isInString;
            } else if (c == '\\') {
                pos++;
            }
        }

        return in.substring(start, pos);
    }

    private JSONException syntaxError(String s) {
        return new JSONException(s + this);
    }

    private String nextString(char quote) throws JSONException {
        /*
         * For strings that are free of escape sequences, we can just extract
         * the result as a substring of the input. But if we encounter an escape
         * sequence, we need to use a StringBuilder to compose the result.
         */
        StringBuilder builder = null;

        /* the index of the first character not yet appended to the builder. */
        int start = pos;

        while (pos < in.length()) {
            int c = in.charAt(pos++);
            if (c == quote) {
                if (builder == null) {
                    // a new string avoids leaking memory
                    return new String(in.substring(start, pos - 1));
                } else {
                    builder.append(in, start, pos - 1);
                    return builder.toString();
                }
            }

            if (c == '\\') {
                if (pos == in.length()) {
                    throw syntaxError("Unterminated escape sequence");
                }
                if (builder == null) {
                    builder = new StringBuilder();
                }
                builder.append(in, start, pos - 1);
                builder.append(readEscapeCharacter());
                start = pos;
            }
        }

        throw syntaxError("Unterminated string");
    }

    private char readEscapeCharacter() throws JSONException {
        char escaped = in.charAt(pos++);
        switch (escaped) {
            case 'u':
                if (pos + 4 > in.length()) {
                    throw syntaxError("Unterminated escape sequence");
                }
                String hex = in.substring(pos, pos + 4);
                pos += 4;
                try {
                    return (char) Integer.parseInt(hex, 16);
                } catch (NumberFormatException nfe) {
                    throw syntaxError("Invalid escape sequence: " + hex);
                }

            case 't':
                return '\t';

            case 'b':
                return '\b';

            case 'n':
                return '\n';

            case 'r':
                return '\r';

            case 'f':
                return '\f';

            case '\'':
            case '"':
            case '\\':
            default:
                return escaped;
        }
    }

    private Object readLiteral() throws JSONException {
        String literal = nextToInternal("{}[]/\\:,=;# \t\f");

        if (literal.length() == 0) {
            throw syntaxError("Expected literal value");
        } else if ("null".equalsIgnoreCase(literal)) {
            return JSONObject.NULL;
        } else if ("true".equalsIgnoreCase(literal)) {
            return Boolean.TRUE;
        } else if ("false".equalsIgnoreCase(literal)) {
            return Boolean.FALSE;
        }

        /* try to parse as an integral type... */
        if (literal.indexOf('.') == -1) {
            int base = 10;
            String number = literal;
            if (number.startsWith("0x") || number.startsWith("0X")) {
                number = number.substring(2);
                base = 16;
            } else if (number.startsWith("0") && number.length() > 1) {
                number = number.substring(1);
                base = 8;
            }
            try {
                long longValue = Long.parseLong(number, base);
                if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
                    return (int) longValue;
                } else {
                    return longValue;
                }
            } catch (NumberFormatException e) {
                /*
                 * This only happens for integral numbers greater than
                 * Long.MAX_VALUE, numbers in exponential form (5e-10) and
                 * unquoted strings. Fall through to try floating point.
                 */
            }
        }

        /* ...next try to parse as a floating point... */
        try {
            return Double.valueOf(literal);
        } catch (NumberFormatException ignored) {
        }

        /* ... finally give up. We have an unquoted string */
        return new String(literal); // a new string avoids leaking memory
    }

    private int nextCleanInternal() throws JSONException {
        while (pos < in.length()) {
            int c = in.charAt(pos++);
            switch (c) {
                case '\t':
                case ' ':
                case '\n':
                case '\r':
                    continue;
                default:
                    return c;
            }
        }

        return -1;
    }

    private String nextToInternal(String excluded) {
        int start = pos;
        for (; pos < in.length(); pos++) {
            char c = in.charAt(pos);
            if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
                return in.substring(start, pos);
            }
        }
        return in.substring(start);
    }
}
